#!/usr/bin/env bash

lockdir="/tmp/filesync.lock"

help() {
  cat<<DOC
  Usage: $(basename $0) (setup|sync|pull|mount|umount)
DOC
}

has? () {
  command -v "$1" &> /dev/null
}

syncDone() {
  if [[ -d "$lockdir" ]]; then
    rm -rf -- "$lockdir"
  fi
}

syncing() {
  # http://mywiki.wooledge.org/BashFAQ/045
  if mkdir "$lockdir"; then
    echo "Aquired lock"
  else
    echo "Syncing already in progress"
    exit 1
  fi
}

install_software() {
  has? encfs && echo "encfs installed" || install encfs
  has? sshfs && echo "sshfs installed" || install sshfs
  has? s3cmd && echo "s3cmd installed" || install s3cmd
  has? inotifywatch && echo "inotifywatch installed" || install inotifywatch
}

install() {
  printf "Installing $1\n"
  if has? apt-get; then
    sudo apt-get install "$1"
  elif has? pacman; then
    sudo pacman -S "$1"
  else
    printf "Can't install $1\n"
  fi
}

mount() {
  if mountpoint -q "$HOME/.backup/crypt"; then
    echo "crypt is mounted"
  else
    echo "mounting crypt"
    sshfs -o uid=$(id -u) -o gid=$(id -g) -o idmap=user -o allow_other \
      tyler@172.16.0.10:/volume1/homes/tyler/backup "$HOME/.backup/crypt"

    # check if it's mounted yet
    if ! mountpoint -q "$HOME/.backup/crypt"; then
      echo "sshfs mount fail"
      exit 1
    fi

  fi

  if mountpoint -q "$HOME/.backup/clear"; then
    echo "clear is mounted"
  else
    echo "mounting clear"
    cat "$HOME/.encfs.conf" | encfs -S "$HOME/.backup/crypt/" "$HOME/.backup/clear/"

    # check if it's mounted yet
    if ! mountpoint -q "$HOME/.backup/clear"; then
      echo "encfs mount fail"
      exit 1
    fi
  fi

  echo "clear and crypt are mounted"
}

umount() {
  fusermount -u "$HOME/.backup/clear"
  fusermount -u "$HOME/.backup/crypt"
}

setup() {
  install_software
  mkdir -p "$HOME/.backup/crypt"
  mkdir -p "$HOME/.backup/clear"
  mkdir -p "$HOME/backup"
  touch "$HOME/.backup/status"
  mount
}

pull() {
  setup
  syncing
  rsync --delete --modify-window=1 -avz "$HOME/.backup/clear/." "$HOME/backup/."
  syncDone
}

sync() {
  mount
  syncing
  rsync --delete --modify-window=1 -avz "$HOME/backup/." "$HOME/.backup/clear/."
  syncDone
}

public() {
  mount
  has? s3cmd && echo "s3cmd installed" || install_s3cmd

  # exit if there is no s3cfg
  [[ ! -r "$HOME/.s3cfg" ]] && exit 1

  syncing
  s3cmd sync --delete-removed "$HOME/backup/Public/" s3://tyler.zone/public/
  s3cmd setacl --acl-public --recursive s3://tyler.zone/public/
  syncDone
}

___doSync() {
  local fd=$(tail -1 "$HOME/.backup/status" | cut -d' ' -f1)
  local public=$(echo "$fd" | grep -c "$HOME/backup/Public")
  local push=$(echo "$fd" | grep -c "$HOME/backup")

  if (( public > 0 )); then
    public
  fi

  if (( push > 0 )); then
    sync
  else
    setup
  fi
}

daemon() {
  setup
  inotifywait -e create,delete,modify,move --format "%w" -r "$HOME/backup" -do "$HOME/.backup/status"
  inotifywait -e create,delete,modify,move --format "%w" -r "$HOME/.backup/clear" -do "$HOME/.backup/status"
  inotifywait -e create,delete,modify,move --format "%w" -r "$HOME/backup/Public" -do "$HOME/.backup/status"

  while true; do
    inotifywait -e modify "$HOME/.backup/status" && ___doSync
  done
}

show() {
  if [[ $1 == 'pids' ]]; then
    ps aux | grep "inotifywait -e create,delete,modify,move --format %w -r $HOME" | grep -v grep | awk '{print $2}'
    ps aux | grep "filesync daemon" | grep -v grep | awk '{print $2}'
    ps aux | grep "inotifywait -e modify $HOME/.backup/status" | grep -v grep | awk '{print $2}'
  else
    ps aux | grep "inotifywait -e create,delete,modify,move --format %w -r $HOME" | grep -v grep
    ps aux | grep "filesync daemon" | grep -v grep
    ps aux | grep "inotifywait -e modify $HOME/.backup/status" | grep -v grep
  fi
}

main() {
  if (( $# < 1 )); then
    help
    exit 1
  fi

  case $1 in
    sync)
      shift
      if (( $# > 0 )); then
        if [[ $1 == 'public' ]]; then
          public
        else
          help
          exit 1
        fi
      else
        sync
      fi
      ;;
    show)
      shift
      if (( $# > 0 )); then
        if [[ $1 == 'pids' ]]; then
          show pids
        else
          help
          exit 1
        fi
      else
        show
      fi
      ;;
    mount) mount ;;
    umount) umount ;;
    setup)
      setup
      ;;
    pull) pull ;;
    public) public ;;
    daemon) daemon ;;
    *)
      help
      exit 1
      ;;
  esac
}

main "$@"
